#region Using Statements
using System;
using System.IO;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
#endregion

namespace SkyBurner
{
    public class Water : BaseDrawableObject
    {
        private VertexBuffer m_waterVertexBuffer;
        private VertexDeclaration m_waterVertexDecl;
        private TextureCube m_cubeMapTexture;
        private int m_nTriangleCount;
        private float m_fWaterMeshSize;
        private float m_fLevel;

        public TextureCube CubeMapTexture
        {
            get { return m_cubeMapTexture; }
            set { m_cubeMapTexture = value; }
        }

        public float Level
        {
            get { return m_fLevel; }
        }

        public Water(BaseGame game)
            : base(game)
        {
            m_fLevel = 0.0f;
            m_waterVertexDecl = new VertexDeclaration(m_Game.GraphicsDevice, VertexPositionNormalTexture.VertexElements);
            m_customEffect = m_Game.ContentManager.Load<Effect>("Data\\Shaders\\WaterCubeMap");
        }

        public void InitWaterMesh(GraphicsDevice pGraphicsDevice, int nPatchSize, float fScale, float fLevel)
        {
            Vector3 vMin = new Vector3(0.0f, 0.0f, 0.0f);
            Vector3 vMax = new Vector3(0.0f, 0.0f, 0.0f);
            VertexPositionNormalTexture[] vTriangle = new VertexPositionNormalTexture[3];
            float fTextureStepX = 1.0f / nPatchSize;
            float fTextureStepZ = 1.0f / nPatchSize;

            m_nTriangleCount = (nPatchSize) * (nPatchSize) * 2;
            m_fWaterMeshSize = nPatchSize * fScale;
            m_fLevel = fLevel;

            // offset to the start position into stream... 
            int nIndex = 0;
            VertexPositionNormalTexture[] waterMesh = new VertexPositionNormalTexture[m_nTriangleCount * 3];
            for (int z = 0; z < nPatchSize; z++)
            {
                for (int x = 0; x < nPatchSize; x++)
                {
                    // first triangle of quad...
                    vTriangle[0].Position.X = x * fScale;
                    vTriangle[0].Position.Y = 0.0f;
                    vTriangle[0].Position.Z = z * fScale;
                    vTriangle[0].TextureCoordinate.X = x * fTextureStepX;
                    vTriangle[0].TextureCoordinate.Y = z * fTextureStepZ;

                    vTriangle[1].Position.X = x * fScale;
                    vTriangle[1].Position.Y = 0.0f;
                    vTriangle[1].Position.Z = (z + 1) * fScale;
                    vTriangle[1].TextureCoordinate.X = x * fTextureStepX;
                    vTriangle[1].TextureCoordinate.Y = (z + 1) * fTextureStepZ;

                    vTriangle[2].Position.X = (x + 1) * fScale;
                    vTriangle[2].Position.Y = 0.0f;
                    vTriangle[2].Position.Z = (z + 1) * fScale;
                    vTriangle[2].TextureCoordinate.X = (x + 1) * fTextureStepX;
                    vTriangle[2].TextureCoordinate.Y = (z + 1) * fTextureStepZ;

                    vTriangle[0].Normal = new Vector3(0.0f, 1.0f, 0.0f);
                    vTriangle[1].Normal = new Vector3(0.0f, 1.0f, 0.0f);
                    vTriangle[2].Normal = new Vector3(0.0f, 1.0f, 0.0f);

                    waterMesh[nIndex++] = vTriangle[0];
                    waterMesh[nIndex++] = vTriangle[1];
                    waterMesh[nIndex++] = vTriangle[2];

                    // second triangle of quad...
                    vTriangle[0].Position.X = x * fScale;
                    vTriangle[0].Position.Y = 0.0f;
                    vTriangle[0].Position.Z = z * fScale;
                    vTriangle[0].TextureCoordinate.X = x * fTextureStepX;
                    vTriangle[0].TextureCoordinate.Y = z * fTextureStepZ;

                    vTriangle[1].Position.X = (x + 1) * fScale;
                    vTriangle[1].Position.Y = 0.0f;
                    vTriangle[1].Position.Z = (z + 1) * fScale;
                    vTriangle[1].TextureCoordinate.X = (x + 1) * fTextureStepX;
                    vTriangle[1].TextureCoordinate.Y = (z + 1) * fTextureStepZ;

                    vTriangle[2].Position.X = (x + 1) * fScale;
                    vTriangle[2].Position.Y = 0.0f;
                    vTriangle[2].Position.Z = z * fScale;
                    vTriangle[2].TextureCoordinate.X = (x + 1) * fTextureStepX;
                    vTriangle[2].TextureCoordinate.Y = z * fTextureStepZ;

                    vTriangle[0].Normal = new Vector3(0.0f, 1.0f, 0.0f);
                    vTriangle[1].Normal = new Vector3(0.0f, 1.0f, 0.0f);
                    vTriangle[2].Normal = new Vector3(0.0f, 1.0f, 0.0f);

                    waterMesh[nIndex++] = vTriangle[0];
                    waterMesh[nIndex++] = vTriangle[1];
                    waterMesh[nIndex++] = vTriangle[2];
                }
            }

            m_waterVertexBuffer = new VertexBuffer(pGraphicsDevice, VertexPositionNormalTexture.SizeInBytes * m_nTriangleCount * 3, ResourceUsage.None, ResourceManagementMode.Automatic);
            m_waterVertexBuffer.SetData<VertexPositionNormalTexture>(waterMesh);
        }

        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {

        }

        public override void Draw(GameTime gameTime, Camera pActiveCamera)
        {
            Matrix mxWorld = Matrix.CreateTranslation(-m_fWaterMeshSize * 0.5f, m_fLevel, -m_fWaterMeshSize * 0.5f + pActiveCamera.Position.Z);
            Matrix mxView = Matrix.CreateLookAt(pActiveCamera.Position, pActiveCamera.LookAt, pActiveCamera.Up);
            Matrix mxProjection = Matrix.CreatePerspectiveFieldOfView(pActiveCamera.FOV, pActiveCamera.AspectRatio, pActiveCamera.NearPlane, pActiveCamera.FarPlane);

            m_Game.GraphicsDevice.VertexDeclaration = m_waterVertexDecl;

            m_Game.GraphicsDevice.RenderState.CullMode = CullMode.None;
            m_Game.GraphicsDevice.RenderState.AlphaBlendEnable = false;

            m_customEffect.Parameters["World"].SetValue(mxWorld);
            m_customEffect.Parameters["View"].SetValue(mxView);
            m_customEffect.Parameters["Projection"].SetValue(mxProjection);
            m_customEffect.Parameters["CameraPosition"].SetValue(pActiveCamera.Position);
            m_customEffect.Parameters["EnvironmentMap"].SetValue(m_cubeMapTexture);

            m_customEffect.Begin();
            foreach (EffectPass pass in m_customEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                m_Game.GraphicsDevice.Vertices[0].SetSource(m_waterVertexBuffer, 0, VertexPositionNormalTexture.SizeInBytes);
                m_Game.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, m_nTriangleCount);
                pass.End();
            }
            m_customEffect.End();
        }
    }
}
